package com.boarsoft.rpc.http.jetty.handler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.boarsoft.common.Util;
import com.boarsoft.rpc.bean.RpcCall;
import com.boarsoft.rpc.bean.RpcInvoking;
import com.boarsoft.rpc.bean.RpcMethodConfig;
import com.boarsoft.rpc.bean.RpcServiceConfig;
import com.boarsoft.rpc.core.RpcContext;
import com.boarsoft.webapp.HttpServiceHandler;

public class RpcJettyHandler extends DefaultHandler implements HttpServiceHandler {
	private static final Logger log = LoggerFactory.getLogger(RpcJettyHandler.class);

	@Autowired
	protected RpcContext rpcContext;

	protected Map<String, IoHandler> ioHandlerMap;

	/** 启动时初始化 */
	protected Map<String, RpcMethodConfig> uriMap = new HashMap<String, RpcMethodConfig>();

	@Override
	public void handle(String target, Request q, HttpServletRequest req, HttpServletResponse rsp)
			throws IOException, ServletException {
		try {
			this.process(req, rsp);
		} finally {
			q.setHandled(true);// 总是返回执行结果
		}
	}

	protected void handle(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
		// 只允许POST方法
		if (!"POST".equalsIgnoreCase(req.getMethod())) {
			rsp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
			return;
		}
		//
		String port = String.valueOf(req.getServerPort());//req.getParameter("port");
		if (Util.strIsEmpty(port)) {
			rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
		}
		String ip = req.getLocalAddr();
		String addr = new StringBuilder().append(ip)//
				.append(":").append(port).toString();
		String contentType = req.getContentType();
		//
		String uri = req.getRequestURI();
		RpcMethodConfig mc = null;
		if (Util.strIsNotEmpty(uri)) {
			mc = uriMap.get(uri);
		}
		// 有传uri则根据uri取配置
		if (mc == null) {
			String sk = req.getHeader("service"); // 可选
			String mk = req.getHeader("method"); // 可选
			if ((Util.strIsEmpty(sk) || Util.strIsEmpty(mk))) {
				rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);
				return;
			}
			RpcServiceConfig sc = rpcContext.getLocalServiceConfigMap().get(sk);
			mc = sc.getMethodConfigMap().get(mk);
		}
		//
		IoHandler ioHandler = ioHandlerMap.get(contentType);
		if (ioHandler == null) {
			rsp.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE);
			return;
		}
		RpcInvoking ri = null;
		try {
			ri = ioHandler.read(mc, addr, req, rsp);
		} catch (Exception e) {
			log.error("Error on read request data", e);
		}
		if (ri == null) {
			rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
		}
		RpcCall co = ri.getRpcCall();
		log.info("{} is invoking {}/{} via handler {}", //
				addr, mc, contentType, ioHandler);
		// 调用服务
		try {
			rpcContext.invoke(co, mc, null, req.getRemoteAddr());
		} catch (Exception e) {
			log.error("Error on process request {}", co, e);
			co.setThrowable(e);
		} finally {
			co.setType(RpcCall.TYPE_RESPONSE);
			co.setArguments(RpcCall.EMPTY_ARGS);
			try {
				ioHandler.write(co, rsp);
			} catch (Exception e) {
				log.error("Error on write response {}", co, e);
			}
		}
	}

	@Override
	public boolean process(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
		this.handle(req, rsp);
		return true;
	}

	public void map(String uri, RpcMethodConfig mc) {
		uriMap.put(uri, mc);
	}

	public RpcContext getRpcContext() {
		return rpcContext;
	}

	public void setRpcContext(RpcContext rpcContext) {
		this.rpcContext = rpcContext;
	}

	public Map<String, IoHandler> getIoHandlerMap() {
		return ioHandlerMap;
	}

	public void setIoHandlerMap(Map<String, IoHandler> ioHandlerMap) {
		this.ioHandlerMap = ioHandlerMap;
	}
}